
#include <BPainter>
#include <BMouseEvent>
#include <BScrollBar>
#include <BKeyEvent>
#include <BStyle>
#include <BCursor>
#include <BSystem>

#include <BTableWidget>
#include "member_BTableWidget.h"
#include "member_BTableItem.h"

using namespace BWE;

#define member					(*(member_BTableWidget*)_ptr)
#define member_allocate()		_ptr = new member_BTableWidget(this)
#define member_release()		delete (member_BTableWidget*)_ptr

BTableWidget::BTableWidget(BWidget* parent) : BScrollArea(parent)
{
	member_allocate();
}
BTableWidget::BTableWidget(int row, int column, BWidget* parent) : BScrollArea(parent)
{
	member_allocate();
	member.items.resize(row, column);
	member.rowHeader.sections.resize(row);
	member.columnHeader.sections.resize(column);
}
BTableWidget::~BTableWidget()
{
	member_release();
}

bool BTableWidget::setRowCount(int rowCount)
{
	if (!member.items.setRow(rowCount))
		return false;
	member.items.setColumn(member.columnHeader.sections.size());
	member.rowHeader.sections.resize(member.items.row());
	member.rowHeader.correctHandle();
	member.selectedItems.clear();
	member.hoverItem = 0;
	member.shiftItem = 0;
	member.dirty = true;
	this->fresh();
	return true;
}
int BTableWidget::rowCount() const
{
	return member.rowHeader.sections.size();
}

bool BTableWidget::setRowLabel(int row, const BString& text)
{
	if (member.rowHeader.sections.check(row))
	{
		IHeaderSection& section = member.rowHeader.sections[row];
		if (section.text != text)
		{
			section.text = text;
			section.dirty = true;
			member.dirty = true;
			this->fresh();
		}
		return true;
	}
	return false;
}
const BString& BTableWidget::rowLabel(int row) const
{
	return member.rowHeader.sections(row).text;
}

bool BTableWidget::setRowAsset(int row, const BValue& asset)
{
	if (member.rowHeader.sections.check(row))
	{
		IHeaderSection& section = member.rowHeader.sections[row];
		section.asset = asset;
		return true;
	}
	return false;
}
const BValue& BTableWidget::rowAsset(int row) const
{
	return member.rowHeader.sections(row).asset;
}

void BTableWidget::setRowVisible(int row, bool visible)
{
	if (member.rowHeader.sections.check(row))
	{
		IHeaderSection& sec = member.rowHeader.sections[row];
		if (sec.visible != visible)
		{
			sec.visible = visible;
			sec.dirty = true;
			member.dirty = true;
			this->fresh();
		}
	}
}
bool BTableWidget::rowVisible(int row) const
{
	return member.rowHeader.sections(row).visible;
}

bool BTableWidget::setColumnCount(int columnCount)
{
	if (!member.items.setColumn(columnCount))
		return false;
	member.columnHeader.sections.resize(columnCount);
	member.columnHeader.correctHandle();
	member.dirty = true;
	this->fresh();
	return true;
}
int BTableWidget::columnCount() const
{
	return member.columnHeader.sections.size();
}

bool BTableWidget::setColumnLabel(int column, const BString& text)
{
	if (member.columnHeader.sections.check(column))
	{
		IHeaderSection& section = member.columnHeader.sections[column];
		if (section.text != text)
		{
			section.text = text;
			section.dirty = true;
			member.dirty = true;
			this->fresh();
		}
		return true;
	}
	return false;
}
const BString& BTableWidget::columnLabel(int column) const
{
	return member.columnHeader.sections(column).text;
}

bool BTableWidget::setColumnAsset(int column, const BValue& asset)
{
	if (member.columnHeader.sections.check(column))
	{
		IHeaderSection& section = member.columnHeader.sections[column];
		section.asset = asset;
		return true;
	}
	return false;
}
const BValue& BTableWidget::columnAsset(int column) const
{
	return member.columnHeader.sections(column).asset;
}

void BTableWidget::setColumnVisible(int column, bool visible)
{
	if (member.columnHeader.sections.check(column))
	{
		IHeaderSection& sec = member.columnHeader.sections[column];
		if (sec.visible != visible)
		{
			sec.visible = visible;
			sec.dirty = true;
			member.dirty = true;
			this->fresh();
		}
	}
}
bool BTableWidget::columnVisible(int column) const
{
	return member.columnHeader.sections(column).visible;
}

int BTableWidget::addRows(int count)
{
	if (member.items.addRow(count))
	{
		member.rowHeader.sections.append(IHeaderSection(), count);
		member.items.setRow(member.rowHeader.sections.size());
		member.dirty = true;
		this->fresh();
		return member.items.row() - count;
	}
	return -1;
}
bool BTableWidget::insertRows(int pos, int count)
{
	if (member.items.insertRow(pos, count))
	{
		member.rowHeader.sections.insert(pos, IHeaderSection(), count);
		for (auto it = member.items.seek(pos + count); it.valid(); it++)
		{
			if (BTableItem* item = *it)
				item_member(item)->row = it.row();
		}
		member.dirty = true;
		this->fresh();
		return true;
	}
	return false;
}
bool BTableWidget::removeRows(int pos, int count)
{
	if (pos < 0 && pos >= member.items.row())
		return false;
	if (count < 1)
		return 0;
	for (int i = 0; i < member.selectedItems.size(); i++)
	{
		BTableItem* item = member.selectedItems[i];
		if (item->row() >= pos && item->row() < pos + count)
			member.selectedItems.remove(i--);
	}
	member.hoverItem = 0;
	member.shiftItem = 0;
	for (int r = pos; r < pos + count; r++)
	{
		for (int c = 0; c < member.items.column(); c++)
		{
			if(BTableItem* item = member.items[r][c])
				this->removeItem(item);
		}
	}
	if (member.items.removeRow(pos, count))
	{
		for (auto it = member.items.seek(pos); it.valid(); it++)
		{
			if (BTableItem* item = *it)
				item_member(item)->row = it.row();
		}
		member.rowHeader.sections.remove(pos, count);
		member.selectedItems.clear();
		member.dirty = true;
		this->fresh();
		return true;
	}
	return false;
}

int BTableWidget::addColumns(int count)
{
	if (member.items.addColumn(count))
	{
		member.columnHeader.sections.append(IHeaderSection(), count);
		member.items.setColumn(member.columnHeader.sections.size());
		member.dirty = true;
		this->fresh();
		return member.items.column() - count;
	}
	return -1;
}
bool BTableWidget::insertColumns(int pos, int count)
{
	if (member.items.insertColumn(pos, count))
	{
		member.columnHeader.sections.insert(pos, IHeaderSection(), count);
		member.dirty = true;
		this->fresh();
		return true;
	}
	return false;
}
bool BTableWidget::removeColumns(int pos, int count)
{
	if (pos < 0 && pos >= member.items.column())
		return false;
	return false;
	if (count < 1)
		return 0;
	for (int i = 0; i < member.selectedItems.size(); i++)
	{
		BTableItem* item = member.selectedItems[i];
		if (item->column() >= pos && item->column() < pos + count)
			member.selectedItems[i] = 0;
	}

	member.selectedItems.remove(0);
	member.hoverItem = 0;
	member.shiftItem = 0;
	if (member.items.removeColumn(pos, count))
	{
		member.columnHeader.sections.remove(pos, count);
		if (member.items.empty())
		{
			member.rowHeader.sections.clear();
		}
		member.dirty = true;
		this->fresh();
		return true;
	}
	return false;
}

bool BTableWidget::setItem(int row, int column, BTableItem* item)
{
	if (!member.items.check(row, column))
		return false;
	if (member.items[row][column] == item)
		return true;
	BTableItem* oldItem = member.items[row][column];
	this->removeItem(oldItem);
	if (item)
	{
		item_member(item)->table = this;
		item_member(item)->row = row;
		item_member(item)->column = column;
		if (item_member(item)->widget)
		{
			this->addChild(item_member(item)->widget);
		}
	}
	member.items[row][column] = item;
	item_member(item)->dirty = true;
	if (member.rowHeader.sections[row].policy != Policy_Fixed)
	{
		member.rowHeader.sections[row].dirty = true;
	}
	if (member.columnHeader.sections[column].policy != Policy_Fixed)
	{
		member.columnHeader.sections[column].dirty = true;
	}
	member.dirty = true;
	this->fresh();
	return true;
}
BTableItem* BTableWidget::setItem(int row, int column, const BString& text)
{
	if (!member.items.check(row, column))
		return 0;
	BTableItemHolder item = this->item(row, column);
	if (!item)
	{
		item = new BTableItem();
		setItem(row, column, item);
	}
	item->setText(text);
	member.dirty = true;
	this->fresh();
	return item;
}
BTableItem* BTableWidget::setItem(int row, int column, Graph graph, const BString& text, Form form)
{
	if (!member.items.check(row, column))
		return 0;
	BTableItemHolder item = this->item(row, column);
	if (!item)
	{
		item = new BTableItem();
		setItem(row, column, item);
	}
	item->setGraph(graph);
	item->setText(text);
	item->setForm(form);
	member.dirty = true;
	this->fresh();
	return item;
}
BTableItem* BTableWidget::setItem(int row, int column, BIcon* icon, const BString& text, Form form)
{
	if (!member.items.check(row, column))
		return 0;
	BTableItemHolder item = this->item(row, column);
	if (!item)
	{
		item = new BTableItem();
		setItem(row, column, item);
	}
	item->setIcon(icon);
	item->setText(text);
	item->setForm(form);
	member.dirty = true;
	this->fresh();
	return item;
}
BTableItem* BTableWidget::setItem(int row, int column, BImage* image, const BString& text, Form form)
{
	if (!member.items.check(row, column))
		return 0;
	BTableItemHolder item = this->item(row, column);
	if (!item)
	{
		item = new BTableItem();
		setItem(row, column, item);
	}
	item->setImage(image);
	item->setText(text);
	item->setForm(form);
	member.dirty = true;
	this->fresh();
	return item;
}
BTableItem* BTableWidget::setItem(int row, int column, BWidget* widget, const BString& text, Form form)
{
	if (!member.items.check(row, column))
		return 0;
	BTableItemHolder item = this->item(row, column);
	if (!item)
	{
		item = new BTableItem();
		setItem(row, column, item);
	}
	item->setWidget(widget);
	item->setText(text);
	item->setForm(form);
	member.dirty = true;
	this->fresh();
	return item;
}

bool BTableWidget::insertItem(BTableItem* item)
{
	if (member.items.column() < 1)
		this->addColumns(1);
	if (!member.items.contain((BTableItem*)0))
		this->addRows(1);
	auto it = member.items.find((BTableItem*)0);
	if (it.valid())
	{
		return setItem(it.row(), it.column(), item);
	}
	return false;
}
BTableItem* BTableWidget::insertItem(const BString& text)
{
	BTableItem* item = new BTableItem(text);
	insertItem(item);
	return item;
}
BTableItem* BTableWidget::insertItem(Graph graph, const BString& text, Form form)
{
	BTableItem* item = new BTableItem(graph, text, form);
	insertItem(item);
	return item;
}
BTableItem* BTableWidget::insertItem(BIcon* icon, const BString& text, Form form)
{
	BTableItem* item = new BTableItem(icon, text, form);
	insertItem(item);
	return item;
}
BTableItem* BTableWidget::insertItem(BImage* image, const BString& text, Form form)
{
	BTableItem* item = new BTableItem(image, text, form);
	insertItem(item);
	return item;
}
BTableItem* BTableWidget::insertItem(BWidget* widget, const BString& text, Form form)
{
	BTableItem* item = new BTableItem(widget, text, form);
	insertItem(item);
	return item;
}

bool BTableWidget::removeItem(const BTableItem* item)
{
	if (!item)
		return false;

	if (item_member(item)->table != this)
		return false;

	member.selectedItems.remove(item);
	if (member.hoverItem == item)
		member.hoverItem = 0;
	if (member.shiftItem == item)
		member.shiftItem = member.selectedItems.first();
	if (item_member(item)->widget)
		this->removeChild(item_member(item)->widget);

	int column = item_member(item)->column;
	int row = item_member(item)->row;
	if (member.items.check(row, column))
	{
		item_member(item)->row = -1;
		item_member(item)->column = -1;

		item_member(item)->table = 0;
		member.items[row][column] = 0;
	}
	member.dirty = true;
	this->fresh();
	return true;
}
void BTableWidget::clearItems()
{
	for (auto it = member.items.begin(); it.valid(); ++it)
	{
		if (BTableItem* item = *it)
		{
			if (item_member(item)->widget)
			{
				this->removeChild(item_member(item)->widget);
			}
		}
	}
	member.rowHeader.sections.clear();
	member.items.setRow(0);
	member.selectedItems.clear();
	member.hoverItem = 0;
	member.shiftItem = 0;
	member.dirty = true;
	this->fresh();
}

bool BTableWidget::moveRow(int row, int destRow)
{
	if (member.rowHeader.sections.move(row, destRow) && member.items.moveRow(row, destRow))
	{
		int minRow = bMin(row, destRow);
		for (auto it = member.items.seek(minRow); it.valid(); it++)
		{
			if (BTableItem* item = *it)
				item_member(item)->row = it.row();
		}
		return true;
	}
	return false;
}
bool BTableWidget::moveColumn(int column, int destColumn)
{
	if (member.columnHeader.sections.move(column, destColumn) && member.items.moveColumn(column, destColumn))
	{
		int minColumn = bMin(column, destColumn);
		for (int r = 0; r < member.items.row(); r++)
		{
			for (int c = minColumn; c < member.items.column(); c++)
			{
				if (BTableItem* item = member.items[r][c])
					item_member(item)->column = c;
			}
		}
		return true;
	}
	return false;
}

BTableItem* BTableWidget::item(int row, int column)
{
	return member.items(row, column);
}
const BTableItem* BTableWidget::item(int row, int column) const
{
	return member.items(row, column);
}

BTableItem* BTableWidget::itemOfText(const BString& text)
{
	for (auto it = member.items.begin(); it.valid(); it++)
	{
		BTableItem* item = *it;
		if (item && item_member(item)->block.text == text)
		{
			return *it;
		}
	}
	return 0;
}
const BTableItem* BTableWidget::itemOfText(const BString& text) const
{
	for (auto it = member.items.begin(); it.valid(); it++)
	{
		const BTableItem* item = *it;
		if (item && item_member(item)->block.text == text)
		{
			return *it;
		}
	}
	return 0;
}

BTableItem* BTableWidget::itemOfText(int column, const BString& text)
{
	if (column >= member.items.column())
		return 0;
	for (int r = 0; r < member.items.row(); r++)
	{
		BTableItem* item = member.items[r][column];
		if (item && item_member(item)->block.text == text)
		{
			return item;
		}
	}
	return 0;
}
const BTableItem* BTableWidget::itemOfText(int column, const BString& text) const
{
	if (column >= member.items.column())
		return 0;
	for (int r = 0; r < member.items.row(); r++)
	{
		const BTableItem* item = member.items[r][column];
		if (item && item_member(item)->block.text == text)
		{
			return item;
		}
	}
	return 0;
}

BTableItem* BTableWidget::itemOfAsset(const BValue& asset)
{
	if (asset.empty())
		return 0;
	for (auto it = member.items.begin(); it.valid(); it++)
	{
		if (*it && (*it)->asset() == asset)
		{
			return *it;
		}
	}
	return 0;
}
const BTableItem* BTableWidget::itemOfAsset(const BValue& asset) const
{
	if (asset.empty())
		return 0;
	for (auto it = member.items.begin(); it.valid(); it++)
	{
		if (*it && (*it)->asset() == asset)
		{
			return *it;
		}
	}
	return 0;
}

BTableItem* BTableWidget::itemOfAsset(int column, const BValue& asset)
{
	if (column >= member.items.column())
		return 0;
	for (int r = 0; r < member.items.row(); r++)
	{
		BTableItem* item = member.items[r][column];
		if (item && item->asset() == asset)
		{
			return item;
		}
	}
	return 0;
}
const BTableItem* BTableWidget::itemOfAsset(int column, const BValue& asset) const
{
	if (column >= member.items.column())
		return 0;
	for (int r = 0; r < member.items.row(); r++)
	{
		const BTableItem* item = member.items[r][column];
		if (item && item->asset() == asset)
		{
			return item;
		}
	}
	return 0;
}

BTableItem* BTableWidget::itemAt(int x, int y)
{
	return member.itemAtPoint(BPoint(x, y));
}
const BTableItem* BTableWidget::itemAt(int x, int y) const
{
	return member.itemAtPoint(BPoint(x, y));
}

BTableItem* BTableWidget::itemAt(const BPoint& pos)
{
	return member.itemAtPoint(pos);
}
const BTableItem* BTableWidget::itemAt(const BPoint& pos) const
{
	return member.itemAtPoint(pos);
}

void BTableWidget::setGridStyle(GridStyle gridStyle)
{
	if (member.gridStyle != gridStyle)
	{
		member.gridStyle = gridStyle;
		fresh();
	}
}
GridStyle BTableWidget::gridStyle() const
{
	return member.gridStyle;
}

void BTableWidget::setRowHeaderShown(bool rowHeaderShown)
{
	if (member.rowHeader.visible != rowHeaderShown)
	{
		member.rowHeader.visible = rowHeaderShown;
		member.dirty = true;
		this->fresh();
	}
}
bool BTableWidget::rowHeaderShown() const
{
	return member.rowHeader.visible;
}

bool BTableWidget::setRowHeight(int row, int height)
{
	if (member.rowHeader.sections.check(row))
	{
		IHeaderSection& sec = member.rowHeader.sections[row];
		if (sec.policy == Policy_Fixed)
			return false;
		if (sec.realSize.height() != height)
		{
			sec.realSize.height() = height;
			sec.dirty = true;
			sec.policy = Policy_Fixed;
			member.dirty = true;
			this->fresh();
		}
		return true;
	}
	return false;
}
int BTableWidget::rowHeight(int row) const
{
	return member.rowHeader.sections[row].rect.height();
}

bool BTableWidget::setRowPolicy(Policy policy)
{
	if (member.rowHeader.sections.empty())
		return false;
	for (int c = 0; c < member.rowHeader.sections.size(); c++)
	{
		IHeaderSection& section = member.rowHeader.sections[c];
		if (section.policy != policy)
		{
			section.policy = policy;
			section.dirty = true;
		}
	}
	member.dirty = true;
	this->fresh();
	return true;
}
bool BTableWidget::setRowPolicy(int row, Policy policy)
{
	if (member.rowHeader.sections.check(row))
	{
		IHeaderSection& section = member.rowHeader.sections[row];
		if (section.policy != policy)
		{
			section.policy = policy;
			section.dirty = true;
			member.dirty = true;
			this->fresh();
		}
		return true;
	}
	return false;
}
Policy BTableWidget::rowPolicy(int row) const
{
	return member.rowHeader.sections(row).policy;
}

void BTableWidget::setRowSpacing(int spacing)
{
	if (member.rowHeader.spacing != spacing)
	{
		member.rowHeader.spacing = spacing;
		member.dirty = true;
		this->fresh();
	}
}
int BTableWidget::rowSpacing() const
{
	return member.rowHeader.spacing;
}

BRect BTableWidget::rowRect(int row) const
{
	if (member.rowHeader.sections.check(row))
	{
		BRect rect = member.rowHeader.sections[row].rect;
		rect.left() = member.columnHeader.sections.first().rect.left();
		rect.right() = member.columnHeader.sections.last().rect.right();
		return rect;
	}
	return BRect();
}
BRect BTableWidget::rowHeaderRect(int row) const
{
	return member.rowHeader.sections[row].rect;
}

void BTableWidget::setColumnHeaderShown(bool columnHeaderShown)
{
	if (member.columnHeader.visible != columnHeaderShown)
	{
		member.columnHeader.visible = columnHeaderShown;
		member.dirty = true;
		this->fresh();
	}
}
bool BTableWidget::columnHeaderShown() const
{
	return member.columnHeader.visible;
}

bool BTableWidget::setColumnWidth(int width)
{
	if (member.columnHeader.sections.empty())
		return false;
	for (int c = 0; c < member.columnHeader.sections.size(); c++)
	{
		IHeaderSection& section = member.columnHeader.sections[c];
		if (section.realSize.width() != width)
		{
			section.realSize.width() = width;
			section.dirty = true;
		}
	}
	member.dirty = true;
	this->fresh();
	return true;
}
bool BTableWidget::setColumnWidth(int column, int width)
{
	if (member.columnHeader.sections.check(column))
	{
		IHeaderSection& section = member.columnHeader.sections[column];
		if (section.realSize.width() != width)
		{
			section.realSize.width() = width;
			section.dirty = true;
			member.dirty = true;
			this->fresh();
		}
		return true;
	}
	return false;
}
int BTableWidget::columnWidth(int column) const
{
	return member.columnHeader.sections(column).rect.width();
}

bool BTableWidget::setColumnPolicy(Policy policy)
{
	if (member.columnHeader.sections.empty())
		return false;
	for (int c = 0; c < member.columnHeader.sections.size(); c++)
	{
		IHeaderSection& section = member.columnHeader.sections[c];
		if (section.policy != policy)
		{
			section.policy = policy;
			section.dirty = true;
		}
	}
	member.dirty = true;
	this->fresh();
	return true;
}
bool BTableWidget::setColumnPolicy(int column, Policy policy)
{
	if (member.columnHeader.sections.check(column))
	{
		IHeaderSection& section = member.columnHeader.sections[column];
		if (section.policy != policy)
		{
			section.policy = policy;
			section.dirty = true;
			member.dirty = true;
			this->fresh();
		}
		return true;
	}
	return false;
}
Policy BTableWidget::columnPolicy(int column) const
{
	return member.columnHeader.sections(column).policy;
}

void BTableWidget::setColumnSortable(int column, bool sortable)
{
	if (member.columnHeader.sections.check(column))
	{
		IHeaderSection& section = member.columnHeader.sections[column];
		if (section.sortable != sortable)
		{
			section.sortable = sortable;
			section.dirty = true;
			member.dirty = true;
			this->fresh();
		}
	}
}
bool BTableWidget::columnSortable(int column) const
{
	return member.columnHeader.sections(column).sortable;
}

void BTableWidget::setColumnSpacing(int spacing)
{
	if (member.columnHeader.spacing != spacing)
	{
		member.columnHeader.spacing = spacing;
		member.dirty = true;
		this->fresh();
	}
}
int BTableWidget::columnSpacing() const
{
	return member.columnHeader.spacing;
}

BRect BTableWidget::columnHeaderRect(int column) const
{
	return member.columnHeader.sections(column).rect;
}
BRect BTableWidget::columnRect(int column) const
{
	if (member.columnHeader.sections.check(column))
	{
		BRect rect = member.columnHeader.sections(column).rect;
		rect.top() = member.rowHeader.sections.first().rect.top();
		rect.bottom() = member.rowHeader.sections.last().rect.bottom();
		return rect;
	}
	return BRect();
}

void BTableWidget::setSelectMode(SelectMode selectMode)
{
	if (member.selectMode != selectMode)
	{
		member.selectMode = selectMode;
		member.selectedItems.clear();
		this->fresh();
	}
}
SelectMode  BTableWidget::selectMode() const
{
	return member.selectMode;
}

bool BTableWidget::setSelection(const BTableItemArray& selection)
{
	bool selectionChanged = false;
	for (int i = 0; i < member.selectedItems.size(); i++)
	{
		BTableItem* item = member.selectedItems[i];
		if (!selection.contain(item))
		{
			item_member(item)->selected = false;
			member.selectedItems.remove(i--);
			emit(Signal_ItemSelected, item);
			selectionChanged = true;
		}
	}
	for (int i = 0; i < selection.size(); i++)
	{
		BTableItem* item = selection[i];
		if (!member.selectedItems.contain(item))
		{
			item_member(item)->selected = true;
			member.selectedItems.append(item);
			emit(Signal_ItemSelected, item);
			selectionChanged = true;
		}
	}
	member.selectedItems = selection;
	if (selectionChanged)
	{
		emit(Signal_SelectionChanged);
		this->fresh();
		return true;
	}
	return false;
}
const BTableItemArray& BTableWidget::selection() const
{
	return member.selectedItems;
}

bool BTableWidget::setItemSelected(BTableItem* item, bool selected)
{
	if (!item)
		return false;
	if (member.selectMode & Select_Rows && item_member(item)->column > 0)
	{
		item = member.items[item_member(item)->row][0];
	}
	if (selected && !member.selectedItems.contain(item))
	{
		if (member.selectMode & Select_Multiple)
		{
			member.selectedItems.clear();
		}
		member.selectedItems.append(item);
		emit(Signal_ItemSelected, item);
		emit(Signal_SelectionChanged);
		this->fresh();
		return true;
	}
	if (!selected && member.selectedItems.contain(item))
	{
		BHolder<BTableItem> holder = item;
		member.selectedItems.remove(item);
		emit(Signal_ItemSelected, item);
		emit(Signal_SelectionChanged);
		this->fresh();
		return true;
	}
	return true;
}
bool BTableWidget::setRowSelected(int row, bool selected)
{
	if (!member.items.check(row, 0))
		return false;
	if (selected)
	{
		if (member.selectMode & Select_Rows)
		{
			BTableItem* item = member.items(row, 0);
			this->setItemSelected(item, true);
		}
		else
		{
			for (int c = 0; c < member.items.column(); c++)
			{
				BTableItem* item = member.items[row][c];
				this->setItemSelected(item, true);
			}
		}
		return true;
	}
	if (!selected)
	{
		if (member.selectMode & Select_Rows)
		{
			BTableItem* item = member.items(row, 0);
			this->setItemSelected(item, false);
		}
		else
		{
			for (int c = 0; c < member.items.column(); c++)
			{
				BTableItem* item = member.items[row][c];
				this->setItemSelected(item, false);
			}
		}
		return true;
	}
	return true;
}
void BTableWidget::clearSelection()
{
	while (member.selectedItems.size())
	{
		BTableItem* item = member.selectedItems.last();
		item->setSelected(false);
		member.selectedItems -= item;
	}
	this->fresh();
}

int BTableWidget::selectedItemCount() const
{
	return member.selectedItems.size();
}
BTableItem* BTableWidget::selectedItem(int index)
{
	return member.selectedItems(index);
}
const BTableItem* BTableWidget::selectedItem(int index) const
{
	return member.selectedItems(index);
}

int BTableWidget::rowOfAsset(const BValue& asset)
{
	for (int r = 0; r < member.rowHeader.sections.size(); r++)
	{
		if (member.rowHeader.sections[r].asset == asset)
			return r;
	}
	return -1;
}
int BTableWidget::columnOfAsset(const BValue& asset)
{
	for (int c = 0; c < member.columnHeader.sections.size(); c++)
	{
		if (member.columnHeader.sections[c].asset == asset)
			return c;
	}
	return -1;
}

int BTableWidget::rowAt(const BPoint& pos) const
{
	return rowAt(pos.y());
}
int BTableWidget::rowAt(int y) const
{
	if (y > this->area().bottom())
		return member.rowHeader.sections.size();
	for (int i = 0; i < member.rowHeader.sections.size(); i++)
	{
		IHeaderSection& sec = member.rowHeader.sections[i];
		BRect rect = sec.rect;
		if (rect.top() < y && rect.bottom() > y)
		{
			return i;
		}
	}
	return -1;
}
int BTableWidget::columnAt(const BPoint& pos) const
{
	return rowAt(pos.x());
}
int BTableWidget::columnAt(int x) const
{
	if (x > this->area().right())
		return member.columnHeader.sections.size();
	for (int i = 0; i < member.columnHeader.sections.size(); i++)
	{
		IHeaderSection& sec = member.columnHeader.sections[i];
		BRect rect = sec.rect;
		if (rect.left() < x && rect.right() > x)
		{
			return i;
		}
	}
	return -1;
}

BRect BTableWidget::cellRect(int row, int column) const
{
	if (member.items.check(row, column))
	{
		const BRect& colRect = member.columnHeader.sections[column].rect;
		const BRect& rowRect = member.rowHeader.sections[row].rect;
		return BRect(colRect.x(), rowRect.y(), colRect.width(), rowRect.height());
	}
	return BRect();
}
bool BTableWidget::scrollToItem(BTableItem* item, Align align)
{
	if (!item)
		return false;
	if (member.dirty)
	{
		member.adjustHeader();
	}
	BRect rect = item->rect();
	return this->scrollToRect(rect);
}
bool BTableWidget::scrollToCell(int row, int column, Align align)
{
	if (!member.items.check(row, column))
		return false;
	if (member.dirty)
	{
		member.adjustHeader();
	}
	const BRect& colRect = member.columnHeader.sections[column].rect;
	const BRect& rowRect = member.rowHeader.sections[row].rect;
	BRect rect(colRect.x(), rowRect.y(), colRect.width(), rowRect.height());
	return this->scrollToRect(rect);
}

bool BTableWidget::sortItems(int column)
{
	if (column < 0)
	{
		for (int i = 0; i < member.columnHeader.sections.size(); i++)
		{
			if (member.columnHeader.sections[i].sortMode)
			{
				column = i;
				break;
			}
		}
	}
	if (!member.columnHeader.sections.check(column))
		return false;
	return member.sortColumn(column);
}

bool BTableWidget::query(const BString& text, BValue& value) const
{
	if (text == "visual-items")
	{
		BTableItemArray& items = value.fill<BTableItemArray>();
		items = member.visualItems;
		return true;
	}
	if (text == "selected-items")
	{
		BTableItemArray& items = value.fill<BTableItemArray>();
		items = member.selectedItems;
		return true;
	}
	return BScrollArea::query(text, value);
}

void BTableWidget::scrollArea()
{
	member.dirty = true;
	this->fresh();
	BScrollArea::scrollArea();
}

void BTableWidget::resizeEvent(const BEvent& event)
{
	BScrollArea::resizeEvent(event);
	member.dirty = true;
}

void BTableWidget::styleEvent(const BEvent& event)
{
	BScrollArea::styleEvent(event);

	if (const BStyle* style = this->realStyle())
	{
		BIcon* upIcon = style->icon(Icon_Arrow_Up);
		member.columnHeader.upIcon = upIcon;
		member.rowHeader.upIcon = upIcon;

		BIcon* downIcon = style->icon(Icon_Arrow_Down);
		member.columnHeader.downIcon = downIcon;
		member.rowHeader.downIcon = downIcon;

		const BValue& columnSpaceValue = style->value(Value_Column_Space);
		if (columnSpaceValue.valid())
			member.columnHeader.spacing = columnSpaceValue;

		const BValue& rowSpaceValue = style->value(Value_Row_Space);
		if (rowSpaceValue.valid())
			member.rowHeader.spacing = rowSpaceValue;

		const BValue& gridStyleValue = style->value(Value_Grid_Style);
		if (gridStyleValue.valid())
			member.gridStyle = gridStyleValue;

		member.itemStyle = (BStyle*)style->sub("item");
		member.headerStyle = (BStyle*)style->sub("header");
	}
	if (const BFont* font = this->font())
	{
		this->verticalScrollBar()->setStep(font->size());
		for (int r = 0; r < member.items.row(); r++)
		{
			for (int c = 0; c < member.items.column(); c++)
			{
				BTableItem* item = member.items[r][c];
				if (!item)
					continue;
				item_member(item)->dirty = true;
			}
		}
		member.dirty = true;
	}

	for (int i = 0; i < member.columnHeader.sections.size(); i++)
		member.columnHeader.sections[i].dirty = true;

	for (int i = 0; i < member.rowHeader.sections.size(); i++)
		member.rowHeader.sections[i].dirty = true;

}
void BTableWidget::freshEvent(const BEvent& event)
{
	if (member.dirty)
	{
		member.adjustHeader();
		member.adjustItemRects();
		member.dirty = false;
	}
	BScrollArea::freshEvent(event);
}
void BTableWidget::paintEvent(const BEvent& event)
{
	BPainter painter(this);
	painter.drawBackground();

	BRect crect = this->centerRect();
	painter.setClip(crect);

	int halfRowSpace = member.rowHeader.spacing / 2;
	int halfColumnSpace = member.columnHeader.spacing / 2;
	if (member.gridStyle & Grid_Horizontal && member.rowHeader.sections.size() > 1)
	{
		if (painter.setColor(Color_Grid_Hor))
		{
			int x0 = member.columnHeader.sections.first().rect.left() - halfColumnSpace;
			int x1 = member.columnHeader.sections.last().rect.right() + halfColumnSpace;
			if (member.rowHeader.sections.size())
			{
				int y = member.rowHeader.sections[0].rect.top() - halfRowSpace;
				painter.drawLine(x0, y, x1, y);
			}
			for (int r = 0; r < member.rowHeader.sections.size(); r++)
			{
				int y = member.rowHeader.sections[r].rect.bottom() + halfRowSpace;
				painter.drawLine(x0, y, x1, y);
			}
		}
	}

	if (member.gridStyle & Grid_Vertical && member.columnHeader.sections.size() > 1)
	{
		if (painter.setColor(Color_Grid_Ver))
		{
			int y0 = member.rowHeader.sections.first().rect.top() - halfRowSpace;
			int y1 = member.rowHeader.sections.last().rect.bottom() + halfRowSpace;
			if (member.columnHeader.sections.size())
			{
				int x = member.columnHeader.sections[0].rect.left() - halfColumnSpace;
				painter.drawLine(x, y0, x, y1);
			}
			for (int c = 0; c < member.columnHeader.sections.size(); c++)
			{
				int x = member.columnHeader.sections[c].rect.right() + halfColumnSpace;
				painter.drawLine(x, y0, x, y1);
			}
		}
	}

	int row_begin = member.rowHeader.show_begin;
	int row_end = member.rowHeader.show_end;
	int col_begin = member.columnHeader.show_begin;
	int col_end = member.columnHeader.show_end;
	if (row_begin >= 0 && col_begin >= 0)
	{
		for (int r = row_begin; r <= row_end; r++)
		{
			if (!member.rowHeader.sections[r].visible)
				continue;
			if (member.selectMode & Select_Rows)
			{
				BTableItem* item = member.items[r][0];
				if (!item)
					continue;
				BRect last = this->cellRect(r, member.items.column() - 1);
				BRect rect = item_member(item)->rect;
				rect.right() = last.right();
				StyleRole colorRole = Color_Item;
				if (item->isSelected())
					colorRole = Color_Item_Checked;
				else if (member.hoverItem == item)
					colorRole = Color_Item_Hovered;
				if (painter.setColor(colorRole))
					painter.fillRect(rect);
			}
			else
			{
				for (int c = col_begin; c <= col_end; c++)
				{
					BTableItem* item = member.items[r][c];
					if (!item)
						continue;
					BRect rect = item_member(item)->rect;
					StyleRole colorRole = Color_Item;
					if (item->isSelected())
						colorRole = Color_Item_Checked;
					else if (member.hoverItem == item)
						colorRole = Color_Item_Hovered;
					if (painter.setColor(colorRole))
					{
						painter.fillRect(rect);
					}
				}
			}
		}
		for (int r = row_begin; r <= row_end; r++)
		{
			if (!member.rowHeader.sections[r].visible)
				continue;
			for (int c = col_begin; c <= col_end; c++)
			{
				BTableItem* item = member.items[r][c];
				if (!item)
					continue;
				painter.setClip(item_member(item)->rect);
				bool selected = member.selectedItems.contain(item);
				if (item_member(item)->ia_imageRect.valid())
				{
					BImage* image = 0;
					if (item_member(item)->icon)
					{
						if (selected)
							image = item_member(item)->icon->image(State_Selected);
						else if (member.hoverItem == item)
							image = item_member(item)->icon->image(State_Hovered);
						else
							image = item_member(item)->icon->image(State_Normal);
					}
					else if (item_member(item)->image)
					{
						image = item_member(item)->image;
					}
					if (image)
					{
						painter.setColor(item_member(item)->color);
						painter.drawImage(item_member(item)->ia_imageRect, image, true);
					}
					else
					{
						if (item_member(item)->graph && item_member(item)->color.a() > 1)
						{
							painter.setColor(item_member(item)->color);
							painter.drawGraph(item_member(item)->rect, item_member(item)->graph);
						}
					}
				}
				if (item_member(item)->ia_textRect.valid() && item_member(item)->block.text.size())
				{
					painter.setColor(Color_Text);
					if (selected)
						painter.setColor(Color_Text_Checked);
					else if (member.hoverItem == item)
						painter.setColor(Color_Text_Hovered);
					item_member(item)->block.paint(painter);
				}
			}
		}
	}
	painter.setClip(0, 0, this->width(), this->height());
	painter.drawPerch();

	if (member.columnHeader.visible)
	{
		painter.setClip(this->rect(Part_Top));
		member.columnHeader.paint(painter);
		painter.setClip(0, 0, this->width(), this->height());
	}

	if (member.rowHeader.visible)
	{
		painter.setClip(this->rect(Part_Left));
		member.rowHeader.paint(painter);
		painter.setClip(0, 0, this->width(), this->height());
	}

	painter.drawMargin();
	painter.drawBorder();

	if (member.selecting)
	{
		painter.setColor(Color_Wire);
		painter.drawRect(member.selectRect);
	}
}

void BTableWidget::keyDownEvent(const BKeyEvent& keyEvent)
{
	Key key = keyEvent.key();
	if (key == Key_LShift || key == Key_RShift)
	{
		member.shiftItem = member.selectedItems.first();
	}
	BScrollArea::keyDownEvent(keyEvent);
}
void BTableWidget::keyUpEvent(const BKeyEvent& keyEvent)
{
	Key key = keyEvent.key();
	if (key == Key_LShift || key == Key_RShift)
	{
		member.shiftItem = 0;
	}
	BScrollArea::keyUpEvent(keyEvent);
}

void BTableWidget::mouseEnterEvent(const BMouseEvent& mouseEvent)
{
	BScrollArea::mouseEnterEvent(mouseEvent);
}
void BTableWidget::mouseLeaveEvent(const BMouseEvent& mouseEvent)
{
	if (member.columnHeader.hoverIndex >= 0)
	{
		member.columnHeader.hoverIndex = -1;
		this->fresh();
	}
	if (member.rowHeader.hoverIndex >= 0)
	{
		member.rowHeader.hoverIndex = -1;
		this->fresh();
	}
	if (member.hoverItem)
	{
		member.hoverItem = 0;
		this->fresh();
	}
	BScrollArea::mouseLeaveEvent(mouseEvent);
}

void BTableWidget::mousePressEvent(const BMouseEvent& mouseEvent)
{
	const BPoint& pos = mouseEvent.pos();
	if (mouseEvent.button() == Button_Left)
	{
		const BRect& topRect = this->rect(Part_Top);
		if (topRect.contain(pos))
		{
			if (member.columnHeader.handle >= 0)
			{
				member.columnHeader.dragBegin(pos);
				this->fresh();
				return;
			}
			if (member.columnHeader.hoverIndex >= 0)
			{
				member.columnHeader.pressed = true;
				this->fresh();
				return;
			}
		}
		const BRect& leftRect = this->rect(Part_Left);
		if (leftRect.contain(pos))
		{
			if (member.rowHeader.handle >= 0)
			{
				member.rowHeader.dragBegin(pos);
				this->fresh();
				return;
			}
			if (member.rowHeader.hoverIndex >= 0)
			{
				member.rowHeader.pressed = true;
				this->fresh();
				return;
			}
		}
		const BRect& centerRect = this->rect(Part_Center);
		if (centerRect.contain(pos) && member.hoverItem == 0)
		{
			member.selecting = true;
			member.pressedPoint = mouseEvent.pos();
			member.selectRect.reset(member.pressedPoint);
		}
	}
	BScrollArea::mousePressEvent(mouseEvent);
}
void BTableWidget::mouseReleaseEvent(const BMouseEvent& mouseEvent)
{
	if (mouseEvent.button() == Button_Left)
	{
		if (member.selecting)
		{
			member.selecting = false;
			this->fresh();
		}
	}
	if (member.columnHeader.draging)
	{
		member.columnHeader.draging = false;
		this->fresh();
	}
	if (member.columnHeader.pressed)
	{
		member.columnHeader.pressed = false;
		this->fresh();
	}
	if (member.rowHeader.draging)
	{
		member.rowHeader.draging = false;
		this->fresh();
	}
	if (member.rowHeader.pressed)
	{
		member.rowHeader.pressed = false;
		this->fresh();
	}
	BScrollArea::mouseReleaseEvent(mouseEvent);
}
void BTableWidget::mouseMoveEvent(const BMouseEvent& mouseEvent)
{
	const BPoint& pos = mouseEvent.pos();
	if (member.selecting)
	{
		member.selectRect.reset(member.pressedPoint);
		member.selectRect.expand(pos);
		BTableItemArray items;
		if (member.selectItemsInside())
		{
			this->emit(Signal_SelectionChanged);
		}
		this->fresh();
		return;
	}

	if (member.columnHeader.draging)
	{
		if (member.columnHeader.drag(pos))
		{
			member.dirty = true;
			this->fresh();
		}
		return;
	}

	if (member.rowHeader.draging)
	{
		if (member.rowHeader.drag(pos))
		{
			member.dirty = true;
			this->fresh();
		}
		return;
	}

	BTableItem* hoveredItem = member.itemAtPoint(pos);
	if (hoveredItem && member.selectMode & Select_Rows)
	{
		hoveredItem = member.items[hoveredItem->row()][0];
	}
	if (member.hoverItem != hoveredItem)
	{
		member.hoverItem = hoveredItem;
		emit(Signal_ItemHovered, hoveredItem);
		this->fresh();
	}

	if (member.columnHeader.visible)
	{
		const BRect& topRect = this->rect(Part_Top);

		int handle = -1;
		if (topRect.contain(pos))
			handle = member.columnHeader.handleUnderPoint(pos);
		if (member.columnHeader.handle != handle)
		{
			member.columnHeader.handle = handle;
			if (handle < 0)
				this->setCursor(Cursor_None);
			else
				this->setCursor(Cursor_SizeHor);
			this->fresh();
		}
		int hoverIndex = -1;
		if (handle < 0 && topRect.contain(pos))
			hoverIndex = member.columnHeader.sectionUnderPoint(pos);
		if (member.columnHeader.hoverIndex != hoverIndex)
		{
			member.columnHeader.hoverIndex = hoverIndex;
			this->fresh();
		}
	}

	if (member.rowHeader.visible)
	{
		const BRect& leftRect = this->rect(Part_Left);

		int handle = -1;
		if (leftRect.contain(pos))
			handle = member.rowHeader.handleUnderPoint(pos);
		if (member.rowHeader.handle != handle)
		{
			member.rowHeader.handle = handle;
			if (handle < 0)
				this->setCursor(Cursor_None);
			else
				this->setCursor(Cursor_SizeVer);
			this->fresh();
		}
		int hoverIndex = -1;
		if (handle < 0 && leftRect.contain(pos))
			hoverIndex = member.rowHeader.sectionUnderPoint(pos);
		if (member.rowHeader.hoverIndex != hoverIndex)
		{
			member.rowHeader.hoverIndex = hoverIndex;
			this->fresh();
		}
	}
	BScrollArea::mouseMoveEvent(mouseEvent);
}

void BTableWidget::mouseClickEvent(const BMouseEvent& mouseEvent)
{
	const BPoint& pos = mouseEvent.pos();
	BTableItem* item = member.itemAtPoint(pos);
	if (mouseEvent.button() == Button_Left)
	{
		if (member.columnHeader.hoverIndex >= 0)
		{
			IHeaderSection& section = member.columnHeader.sections[member.columnHeader.hoverIndex];
			if (section.sortable)
			{
				if (section.sortMode == 0)
					section.sortMode = -1;
				else
					section.sortMode = -section.sortMode;
				for (int i = 0; i < member.columnHeader.sections.size(); i++)
				{
					IHeaderSection& sec = member.columnHeader.sections[i];
					if (member.columnHeader.hoverIndex != i)
						sec.sortMode = 0;
				}
				member.sortColumn(member.columnHeader.hoverIndex);
				this->fresh();
			}
			return;
		}
		if (item && member.selectMode & Select_Rows)
		{
			item = member.items[item->row()][0];
		}
		if (member.selectMode & Select_Multiple)
		{
			if (item && BSystem::KeyState(Key_LShift))
			{
				if (member.shiftItem == 0)
				{
					member.shiftItem = item;
					member.selectedItems.append(item);
					emit(Signal_ItemSelected, item);
					this->fresh();
				}
				else
				{
					BArray<BTableItem*> items;
					int row_begin = bMin(item->row(), member.shiftItem->row());
					int row_end = bMax(item->row(), member.shiftItem->row());

					items.resize(row_end - row_begin);
					items.reset();

					for (int r = row_begin; r <= row_end; r++)
					{
						item = member.items[r][0];
						items.append(item);
					}

					for (int i = 0; i < member.selectedItems.size(); i++)
					{
						item = member.selectedItems[i];
						if (!items.contain(item))
						{
							i--;
							member.selectedItems.remove(item);
							emit(Signal_ItemSelected, item);
						}
					}
					for (int i = 0; i < items.size(); i++)
					{
						item = items[i];
						if (!member.selectedItems.contain(item))
						{
							member.selectedItems.append(item);
							emit(Signal_ItemSelected, item);
						}
					}
					emit(Signal_SelectionChanged);
					this->fresh();
				}
			}
			else if (item && BSystem::KeyState(Key_LCtrl))
			{
				if (member.selectedItems.contain(item))
				{
					member.selectedItems.remove(item);
					emit(Signal_ItemSelected, item);
				}
				else
				{
					member.selectedItems.append(item);
					emit(Signal_ItemSelected, item);
				}
				emit(Signal_SelectionChanged);
				this->fresh();
			}
			else
			{
				for (int i = 0; i < member.selectedItems.size(); i++)
				{
					BTableItem* old_item = member.selectedItems[i];
					if (old_item != item)
					{
						i--;
						member.selectedItems.remove(old_item);
						emit(Signal_ItemSelected, old_item);
					}
				}
				if (member.selectedItems.empty() && item)
				{
					member.selectedPos = pos;
					member.selectedTime = clock();
					member.selectedItems.append(item);
					emit(Signal_ItemSelected, item);
				}
				emit(Signal_SelectionChanged);
				this->fresh();
			}
		}
		else
		{
			for (int i = 0; i < member.selectedItems.size(); i++)
			{
				BTableItem* selectedItem = member.selectedItems[i];
				if (selectedItem != item)
				{
					member.selectedItems.remove(i);
					i--;
					emit(Signal_ItemSelected, selectedItem);
				}
			}
			if (item && member.selectedItems.empty())
			{
				member.selectedPos = pos;
				member.selectedTime = clock();
				member.selectedItems.append(item);
				emit(Signal_ItemSelected, item);
			}
			emit(Signal_SelectionChanged);
			this->fresh();
		}
		emit(Signal_ItemClicked, item);
	}
	else if (mouseEvent.button() == Button_Right)
	{
		emit(Signal_ItemRightClicked, item);
	}
	BScrollArea::mouseClickEvent(mouseEvent);
}
void BTableWidget::mouseDoubleClickEvent(const BMouseEvent& mouseEvent)
{
	if (mouseEvent.button() == Button_Left)
	{
		const BPoint& pos = mouseEvent.pos();

		BTableItem* item = member.itemAtPoint(pos);
		if (item && member.selectMode & Select_Rows)
		{
			item = member.items[item->row()][0];
		}

		emit(Signal_ItemDoubleClicked, item);
	}
	BScrollArea::mouseDoubleClickEvent(mouseEvent);
}
